﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.IO.Packaging;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Xps.Packaging;
using System.Windows.Xps.Serialization;
using System.Printing;
using Microsoft.Win32;
using BOL.Apps.GeneNetworkBrowser.Analysis.SubNetwork;
using BOL.Apps.GeneNetworkBrowser.Databases;
using BOL.Apps.GeneNetworkBrowser.IO;
using BOL.Apps.GeneNetworkBrowser.Controls;
using BOL.Apps.GeneNetworkBrowser.Networks;
using BOL.Apps.GeneNetworkBrowser.ViewModels;

namespace BOL.Apps.GeneNetworkBrowser.Windows
{
    public partial class MainWindow : IDialogProvider
    {
        #region Private variables

        private const string LayoutFile = "Layout.xml";
        private const string DefaultLayout = "BOL.Apps.GeneNetworkBrowser.Resources.DefaultLayout.xml";

        #endregion

        #region IDialogProvider implementation

        public string NewProjectFileDialog()
        {
            var sfd = new SaveFileDialog {Title = "New project"};
            if (Directory.Exists(ViewModel.GeneNetworkBrowserFolder))
                sfd.InitialDirectory = ViewModel.GeneNetworkBrowserFolder;
            else
                sfd.RestoreDirectory = true;
            var result = sfd.ShowDialog();

            return result.Value ? sfd.FileName : null;
        }

        public string OpenProjectFileDialog()
        {
            var ofd = new OpenFileDialog();
            ofd.Title = "Open project";
            ofd.Filter = "Project files|*.project";
            if (Directory.Exists(ViewModel.GeneNetworkBrowserFolder))
                ofd.InitialDirectory = ViewModel.GeneNetworkBrowserFolder;
            else
                ofd.RestoreDirectory = true;
            var result = ofd.ShowDialog();

            return result.Value ? ofd.FileName : null;
        }

        public string OpenGeneValueFileDialog()
        {
            var ofd = new OpenFileDialog();
            ofd.Title = "Open gene value file";
            ofd.Filter = "Text files|*.txt;*.csv|All Files|*.*";
            ofd.RestoreDirectory = true;
            var result = ofd.ShowDialog();

            return result.Value ? ofd.FileName : null;
        }

        public string[] OpenNetworkFilesDialog()
        {
            var ofd = new OpenFileDialog();
            ofd.Title = "Open network files";
            ofd.Filter = "Network files|*.gxl;*.gml;*.xml;*.xgmml|All Files|*.*";
            ofd.RestoreDirectory = true;
            ofd.Multiselect = true;
            var result = ofd.ShowDialog();

            return result.Value ? ofd.FileNames : null;
        }

        public string[] OpenAnalysisFilesDialog()
        {
            var ofd = new OpenFileDialog();
            ofd.Title = "Open analysis files";
            ofd.Filter = "Analysis files|*.analysis;*.xml|All Files|*.*";
            ofd.RestoreDirectory = true;
            ofd.Multiselect = true;
            var result = ofd.ShowDialog();

            return result.Value ? ofd.FileNames : null;
        }

        public string SaveAsProjectFileDialog()
        {
            var sfd = new SaveFileDialog();
            sfd.Title = "Save a project file";
            sfd.Filter = "Project file|*.project|All Files|*.*";
            sfd.RestoreDirectory = true;
            sfd.FileName = ViewModel.ActiveDocument.FilePath;

            var result = sfd.ShowDialog();

            return result.Value ? sfd.FileName : null;
        }

        public string SaveAsNetworkFileDialog()
        {
            var sfd = new SaveFileDialog();
            sfd.Title = "Save a project file";
            sfd.Filter = "Network files|*.gxl;*.gml;*.xgmml;*.xml|All Files|*.*";
            sfd.RestoreDirectory = true;
            sfd.FileName = ViewModel.ActiveDocument.FilePath;

            var result = sfd.ShowDialog();

            return result.Value ? sfd.FileName : null;
        }

        public string SaveAsAnalysisFileDialog()
        {
            var sfd = new SaveFileDialog();
            sfd.Title = "Save a project file";
            sfd.Filter = "Analysis files|*.analysis|All Files|*.*";
            sfd.RestoreDirectory = true;
            sfd.FileName = ViewModel.ActiveDocument.FilePath;

            var result = sfd.ShowDialog();

            return result.Value ? sfd.FileName : null;
        }

        /// <summary>
        /// Display an error message dialog box.
        /// </summary>
        public void ErrorMessage(string message)
        {
            MessageBox.Show(this, message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }

        /// <summary>
        /// Allow the user to confirm whether they want to close a modified document.
        /// </summary>
        public bool QueryCloseModifiedDocument(DocumentViewModel document)
        {
            string message = String.Format("{0} has been modified but not saved.\nDo you really want to close it?", document.FileName);
            var result = MessageBox.Show(this, message, "File modified but not saved", MessageBoxButton.YesNo, MessageBoxImage.Warning);
            
            return result == MessageBoxResult.Yes;
        }
        
        /// <summary>
        /// Allow the user to confirm whether they want to close the application when 1 or more documents are modified.
        /// </summary>
        public bool QueryCloseApplicationWhenDocumentsModified()
        {
            var result = MessageBox.Show(this, "One or more open files have been modified but not saved.\nDo you really want to exit?", "File(s) modified but not saved", MessageBoxButton.YesNo, MessageBoxImage.Warning);
            
            return result == MessageBoxResult.Yes;
        }

        #endregion

        #region AvalonDockHost menu

        ///// <summary>
        ///// Event raised when the 'OpenFile' command is executed.
        ///// </summary>
        //private void OpenFile_Executed(object sender, ExecutedRoutedEventArgs e)
        //{
        //    ViewModel.OpenFile();
        //}

        ///// <summary>
        ///// Event raised when the 'SaveFile' command is executed.
        ///// </summary>
        //private void SaveFile_Executed(object sender, ExecutedRoutedEventArgs e)
        //{
        //    ViewModel.SaveFile();
        //}

        ///// <summary>
        ///// Event raised when the 'SaveFileAs' command is executed.
        ///// </summary>
        //private void SaveFileAs_Executed(object sender, ExecutedRoutedEventArgs e)
        //{
        //    ViewModel.SaveFileAs();
        //}

        ///// <summary>
        ///// Event raised when the 'SaveAllFiles' command is executed.
        ///// </summary>
        //private void SaveAllFiles_Executed(object sender, ExecutedRoutedEventArgs e)
        //{
        //    ViewModel.SaveAllFiles();
        //}

        ///// <summary>
        ///// Event raised when the 'CloseFile' command is executed.
        ///// </summary>
        //private void CloseFile_Executed(object sender, ExecutedRoutedEventArgs e)
        //{
        //    ViewModel.CloseFile();
        //}

        ///// <summary>
        ///// Event raised when the 'CloseAllFiles' command is executed.
        ///// </summary>
        //private void CloseAllFiles_Executed(object sender, ExecutedRoutedEventArgs e)
        //{
        //    ViewModel.CloseAllFiles();
        //}

        ///// <summary>
        ///// Event raised when the 'ShowAllPanes' command is executed.
        ///// </summary>
        //private void ShowAllPanes_Executed(object sender, ExecutedRoutedEventArgs e)
        //{
        //    ViewModel.ShowAllPanes();
        //}

        ///// <summary>
        ///// Event raised when the 'HideAllPanes' command is executed.
        ///// </summary>
        //private void HideAllPanes_Executed(object sender, ExecutedRoutedEventArgs e)
        //{
        //    ViewModel.HideAllPanes();
        //}

        ///// <summary>
        ///// Exit the application.
        ///// </summary>
        //private void Exit_Executed(object sender, ExecutedRoutedEventArgs e)
        //{
        //    Close();
        //}

        /// <summary>
        /// Event raised when AvalonDock has loaded.
        /// </summary>
        private void AvalonDockHostLoaded(object sender, EventArgs e)
        {
            // If there is already a saved layout file, restore AvalonDock layout from it.
            if (File.Exists(LayoutFile))
                _avalonDockHost._dockingManager.RestoreLayout(LayoutFile);
            else
            {
                //
                // This line of code can be uncommented to get a list of resources.
                //
                //string[] names = GetType().Assembly.GetManifestResourceNames();

                // Load the default AvalonDock layout from an embedded resource.
                var assembly = Assembly.GetExecutingAssembly();

                using (var stream = assembly.GetManifestResourceStream(DefaultLayout))
                {
                    _avalonDockHost._dockingManager.RestoreLayout(stream);
                }
            }
        }

        /// <summary>
        /// Event raised when a document is being closed by clicking the 'X' button in AvalonDock.
        /// </summary>
        private void AvalonDockHostDocumentClosing(object sender, DocumentClosingEventArgs e)
        {
            var document = (DocumentViewModel)e.Document;
            if (!ViewModel.QueryCanCloseFile(document))
            {
                e.Cancel = true;
            }
        }

        #endregion

        #region Public properties

        public MainWindowViewModel ViewModel { get { return DataContext as MainWindowViewModel; } }

        #endregion

        #region Constructor

        public MainWindow()
        {
            InitializeComponent();
        }

        #endregion

        #region Menu methods

        private void CommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            var target = e.Source as System.Windows.Controls.Control;

            if (target != null)
                e.CanExecute = true;
            else
                e.CanExecute = false;
        }

        #region File menu methods

        private void NewCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            ViewModel.NewProject();
        }

        private void OpenCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            ViewModel.OpenFile();
        }

        private void SaveCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            SaveProject();
        }

        private void SaveAsCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            var document = ViewModel.ActiveDocument;
            if (document is NetworkDocumentViewModel)
            {
                Network network = (document as NetworkDocumentViewModel).Network;

                var sfd = new System.Windows.Forms.SaveFileDialog();
                sfd.Title = "Save a project file";
                sfd.Filter = "Project file|*.prj|Network files|*.gxl;*.gml;*.xgmml;*.xml;*.svg|Analysis files|*.ana;*.res|All Files|*.*";
                sfd.RestoreDirectory = true;
                var dialogResult = sfd.ShowDialog();

                if (dialogResult == System.Windows.Forms.DialogResult.OK)
                {
                    var fi = new FileInfo(sfd.FileName);

                    try
                    {
                        switch (sfd.FilterIndex)
                        {
                            default:
                            case 1: // Project file
                                //var bifw = new BIFWriter(sfd.FileName, _bn);
                                //bifw.Write(_bn);
                                SaveProject();
                                break;
                            case 2: // Network files

                                if (fi.Extension == ".gxl")
                                {
                                    //var gxlw = new GXLWriter(network, fi.FullName);
                                    //gxlw.Write();
                                    //gxlw.Close();
                                }
                                else if (fi.Extension == ".gml")
                                {
                                    //var gxlw = new GMLWriter(network, fi.FullName);
                                    //gxlw.Write();
                                    //gxlw.Close();
                                }
                                else if (fi.Extension == ".xml" || fi.Extension == ".xgmml")
                                {
                                    var graphMLW = new GraphMLWriter(network, fi.FullName);
                                    graphMLW.Write();
                                    graphMLW.Close();
                                }
                                else if (fi.Extension == ".svg")
                                {
                                    //var svgW = new SVGWriter(network, fi.FullName);
                                    //svgW.Write();
                                    //svgW.Close();
                                }
                                else
                                {
                                    Console.WriteLine("");
                                }
                                break;
                            case 3: // Project file
                                //var bifw = new BIFWriter(sfd.FileName, _bn);
                                //bifw.Write(_bn);
                                break;
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
            }
        }

        private void SaveProject()
        {
            //var projw = new ProjectWriter(sfd.FileName, _currentProject);
            //projw.Write();
            //projw.Close();
        }

        private void ImportText(object sender, RoutedEventArgs e)
        {
            ViewModel.OpenFile();
        }

        private void ImportExcel(object sender, RoutedEventArgs e)
        {
            ViewModel.OpenFile();
        }

        private void ExportCanvasToImage(object sender, RoutedEventArgs e)
        {
            try
            {
                var dc = (NetworkDocument)_avalonDockHost.ActiveDocument;
                var zoom = dc._zoomControl;
                
                var sfd = new Microsoft.Win32.SaveFileDialog();
                sfd.Title = "Export Canvas to Image";
                sfd.Filter = "Image files|*.bmp,*.png,*.jpg,*.png,*.tif,*.xps|BMP - Windows Bitmap|*.bmp|GIF - CompuServe GIF|*.png|JPG - JPEG Image|*.jpg|PNG - Portable Network Graphics|*.png|TIF - Tagged Image File|*.tif|XPS - XML Paper Specification|*.xps";
                sfd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
                
                var dialogResult = sfd.ShowDialog();
                if (dialogResult.HasValue && dialogResult.Value)
                {
                    var path = sfd.FileName;
                    
                    switch (sfd.FilterIndex)
                    {
                        case 2: // Bmp
                            ExportBitmap(zoom, path, ImageType.Bmp);
                            break;
                        case 3: // Gif
                            ExportBitmap(zoom, path, ImageType.Gif);
                            break;
                        case 4: // Jpg
                            ExportBitmap(zoom, path, ImageType.Jpeg);
                            break;
                        case 5:
                        default: // Png
                            ExportBitmap(zoom, path, ImageType.Png);
                            break;
                        case 6: // Tif
                            ExportBitmap(zoom, path, ImageType.Tiff);
                            break;
                        case 7: // Xps
                            ExportVector(zoom, path);
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Export Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }


        private void ExportBitmap(Control control, string path, ImageType imageType)
        {
            Transform transform = control.LayoutTransform;
            control.LayoutTransform = null;

            var renderBitmap = new RenderTargetBitmap((int)control.ActualWidth, (int)control.ActualHeight, 96d, 96d, PixelFormats.Pbgra32);
            renderBitmap.Render(control);

            using (var fs = new FileStream(path, FileMode.Create))
            {
                BitmapEncoder encoder = null;

                if (imageType == ImageType.Bmp)
                    encoder = new BmpBitmapEncoder();
                else if (imageType == ImageType.Gif)
                    encoder = new GifBitmapEncoder();
                else if (imageType == ImageType.Jpeg)
                    encoder = new JpegBitmapEncoder();
                else if (imageType == ImageType.Tiff)
                    encoder = new TiffBitmapEncoder();
                else
                    encoder = new PngBitmapEncoder();

                encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
                encoder.Save(fs);
            }

            control.LayoutTransform = transform;
        }

        private void ExportVector(Control control, string path)
        {
            Transform transform = control.LayoutTransform;
            control.LayoutTransform = null;

            try
            {
                using (var xpsd = new XpsDocument(path, FileAccess.ReadWrite))
                {
                    var fixedDocument = new FixedDocument();
                    var fixedPage = new FixedPage();
                    var pageContent = new PageContent();

                    // Create first page of document

                    fixedPage.Children.Add(control);
                    ((IAddChild)pageContent).AddChild(fixedPage);
                    fixedDocument.Pages.Add(pageContent);

                    var xw = XpsDocument.CreateXpsDocumentWriter(xpsd);
                    xw.Write(fixedDocument);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            control.LayoutTransform = transform;
            //documentViewer1.Document = fixedDoc;
        }


        private DrawingGroup GetDrawingGroup(Visual visual)
        {
            DrawingGroup drawingGroup = VisualTreeHelper.GetDrawing(visual);
            EnumDrawingGroup(drawingGroup);

            return drawingGroup;
        }

        private void EnumDrawingGroup(DrawingGroup drawingGroup)
        {
            DrawingCollection dc = drawingGroup.Children;

            // Enumerate the drawings in the DrawingCollection.
            foreach (Drawing drawing in dc)
            {
                // If the drawing is a DrawingGroup, call the function recursively.
                if (drawing.GetType() == typeof(DrawingGroup))
                {
                    EnumDrawingGroup((DrawingGroup)drawing);
                }
                else if (drawing.GetType() == typeof(GeometryDrawing))
                {
                    // Perform action based on drawing type.  
                }
                else if (drawing.GetType() == typeof(ImageDrawing))
                {
                    // Perform action based on drawing type.
                }
                else if (drawing.GetType() == typeof(GlyphRunDrawing))
                {
                    // Perform action based on drawing type.
                }
                else if (drawing.GetType() == typeof(VideoDrawing))
                {
                    // Perform action based on drawing type.
                }
            }
        }

        private void PrintCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            var activeDocument = _avalonDockHost.ActiveDocument;

            if (activeDocument != null)
            {
                FrameworkElement visual = null;
                if (activeDocument is NetworkDocument)
                    visual = ((NetworkDocument)activeDocument)._networkGraphLayout;

                PrintVisual(visual, ((NetworkDocument)activeDocument).Title, 30);
            }
            else
                MessageBox.Show("No document to print!", "Print Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }

        private void PrintVisual(FrameworkElement visual, string title, double minimumMargin)
        {
            var dialog = new PrintDialog();

            if (dialog.ShowDialog() == true)
            {
                // Gets the paper size
                PrintCapabilities capabilities = dialog.PrintQueue.GetPrintCapabilities(dialog.PrintTicket); 

                // Estimates margin
                double pageMargin = Math.Min(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight);
                double additionalMargin = Math.Max(0, minimumMargin - pageMargin); 
                
                // Estimates page size
                Size pageSize = new Size(capabilities.PageImageableArea.ExtentWidth - additionalMargin * 2, capabilities.PageImageableArea.ExtentHeight - additionalMargin * 2); 
                
                // Gets scale of the print wrt to screen of WPF visual 
                double scale = Math.Min(pageSize.Width / visual.ActualWidth, pageSize.Height / visual.ActualHeight); 
                Size printSize = new Size(visual.ActualWidth * scale, visual.ActualHeight * scale); 
                Point upperLeft = new Point(capabilities.PageImageableArea.OriginWidth + additionalMargin, capabilities.PageImageableArea.OriginHeight + additionalMargin); 
                
                // Transforms the Visual to scale 
                visual.LayoutTransform = new ScaleTransform(scale, scale); 
                visual.Measure(printSize); 
                visual.Arrange(new Rect(upperLeft, printSize));

                dialog.PrintVisual(visual, title);
            }
        }

        private void PrintPreviewCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            var activeDocument = _avalonDockHost.ActiveDocument;

            if (activeDocument != null)
            {
                FrameworkElement visual = null;
                if (activeDocument is NetworkDocument)
                    visual = ((NetworkDocument)activeDocument)._networkGraphLayout;

                PreviewVisual(visual);
            }
            else
            {
                MessageBox.Show("No document to preview!", "Preview Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void PreviewVisual(FrameworkElement visual)
        {
            visual.Measure(new Size(Int32.MaxValue, Int32.MaxValue));
            Size visualSize = visual.DesiredSize;
            visual.Arrange(new Rect(new Point(0, 0), visualSize));
            MemoryStream stream = new MemoryStream();
            string pack = "pack://temp.xps";
            Uri uri = new Uri(pack);
            DocumentPaginator paginator;
            XpsDocument xpsDocument;

            using (Package container = Package.Open(stream, FileMode.Create))
            {
                PackageStore.AddPackage(uri, container);
                using (xpsDocument = new XpsDocument(container, CompressionOption.Fast, pack))
                {
                    XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(xpsDocument), false);
                    rsm.SaveAsXaml(visual);
                    paginator = ((IDocumentPaginatorSource)xpsDocument.GetFixedDocumentSequence()).DocumentPaginator;
                    paginator.PageSize = visualSize;

                    var printPreview = new PrintPreview();
                    printPreview.Owner = this;
                    printPreview.Document = xpsDocument.GetFixedDocumentSequence();
                    printPreview.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                    printPreview.ResizeMode = System.Windows.ResizeMode.NoResize;
                    printPreview.ShowDialog();
                }
                PackageStore.RemovePackage(uri);
            }
        }

        private void CloseCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            SaveLayout(sender, e);

            for (int i = App.Current.Windows.Count - 1; i >= 0; i--)
                App.Current.Windows[i].Close();
        }

        #endregion

        #region Edit menu methods

        private void UndoCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void RedoCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void CopyCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void CutCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void PasteCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void DeleteCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void FindCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            //if (_findObject.State == DockableContentState.None || _findObject.State == DockableContentState.Hidden)
            //    _findObject.ShowAsFloatingWindow(AvalonDockHost, true);
            //else
            //    _findObject.Hide();
        }

        private void SelectAllCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (_avalonDockHost.ActiveDocument != null)
            {
                var networkDocument = _avalonDockHost.ActiveDocument as NetworkDocument;
                //networkDocument.SelectAll();
            }
        }

        private void PropertiesCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            var pw = new PreferencesWindow();

            pw.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            pw.ResizeMode = System.Windows.ResizeMode.NoResize;
            pw.ShowDialog();
        }

        #endregion

        #region View menu methods

        private void MenuItemView_ProjectPane_Click(object sender, RoutedEventArgs e)
        {
            //if (_projectTreeView.State == DockableContentState.Hidden)
            //    _projectTreeView.Show();
            //else if (_projectTreeView.State == DockableContentState.Docked || _projectTreeView.State == DockableContentState.DockableWindow || _projectTreeView.State == DockableContentState.AutoHide || _projectTreeView.State == DockableContentState.None)
            //    _projectTreeView.Activate();
        }

        private void MenuItemView_PropertyPane_Click(object sender, RoutedEventArgs e)
        {
            //if (_propertyGridView.State == DockableContentState.Hidden)
            //    _propertyGridView.Show();
            //else if (_propertyGridView.State == DockableContentState.Docked || _propertyGridView.State == DockableContentState.DockableWindow || _propertyGridView.State == DockableContentState.AutoHide || _propertyGridView.State == DockableContentState.None)
            //    _propertyGridView.Activate();
        }

        private void MenuItemView_AnnotationPane_Click(object sender, RoutedEventArgs e)
        {
            //if (_annotationPane.State == DockableContentState.Hidden)
            //    _annotationPane.Show();
            //else if (_annotationPane.State == DockableContentState.Docked || _annotationPane.State == DockableContentState.DockableWindow || _annotationPane.State == DockableContentState.AutoHide || _annotationPane.State == DockableContentState.None)
            //    _annotationPane.Activate();
        }

        private void MenuItemView_OutputPane_Click(object sender, RoutedEventArgs e)
        {
            //if (_output.State == DockableContentState.Hidden)
            //    _output.Show();
            //else if (_output.State == DockableContentState.Docked || _output.State == DockableContentState.DockableWindow || _output.State == DockableContentState.AutoHide || _output.State == DockableContentState.None)
            //    _output.Activate();
        }

        private void MenuItemView_FilterPane_Click(object sender, RoutedEventArgs e)
        {
            //if (_networkSelector.State == DockableContentState.Hidden)
            //    _networkSelector.Show();
            //else if (_networkSelector.State == DockableContentState.Docked || _networkSelector.State == DockableContentState.DockableWindow || _networkSelector.State == DockableContentState.AutoHide || _networkSelector.State == DockableContentState.None)
            //    _networkSelector.Activate();
        }

        private void MenuItemView_AnalysisPane_Click(object sender, RoutedEventArgs e)
        {
            //if (_networkSelector.State == DockableContentState.Hidden)
            //    _networkSelector.Show();
            //else if (_networkSelector.State == DockableContentState.Docked || _networkSelector.State == DockableContentState.DockableWindow || _networkSelector.State == DockableContentState.AutoHide || _networkSelector.State == DockableContentState.None)
            //    _networkSelector.Activate();
        }

        private void IncreaseZoomCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (_avalonDockHost.ActiveDocument != null)
            {
                var networkDocument = _avalonDockHost.ActiveDocument as NetworkDocument;
                networkDocument._zoomControl.Zoom *= 1.05;
            }
        }

        private void DecreaseZoomCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (_avalonDockHost.ActiveDocument != null)
            {
                var networkDocument = _avalonDockHost.ActiveDocument as NetworkDocument;
                networkDocument._zoomControl.Zoom *= 0.95;
            }
        }

        private void ZoomToFillCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (_avalonDockHost.ActiveDocument != null)
            {
                var networkDocument = _avalonDockHost.ActiveDocument as NetworkDocument;
                networkDocument._zoomControl.ZoomToFill();
            }
        }

        private void FullScreenCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (WindowStyle != WindowStyle.None)
            {
                WindowStyle = WindowStyle.None;
                WindowState = WindowState.Maximized;
            }
            else
            {
                WindowStyle = WindowStyle.SingleBorderWindow;
                WindowState = WindowState.Normal;
            }
        }

        #endregion

        #region Analysis menu methods

        private void MenuItemAnalysis_AddCustomValuesToGenes_Click(object sender, RoutedEventArgs e)
        {
            var gvw = new GeneValuesWindow();
            gvw.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            gvw.ResizeMode = System.Windows.ResizeMode.NoResize;

            if (!gvw.ShowDialog().Value)
                MessageBox.Show("Fail to add custom values!", "Custom Values Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }

        private void MenuItemAnalysis_Compile_HGR_Click(object sender, RoutedEventArgs e)
        {
            //var hgrw = new HGRWriter("hgr.bin");
            
            //hgrw.Write();
            //hgrw.Close();

            //var aw = new AnnotationWindow();
            //aw.ShowDialog();
        }

        private void MenuItemAnalysis_Compile_A24R_Click(object sender, RoutedEventArgs e)
        {
            //var a24rw = new A24RWriter("cnaml.bin");

            //a24rw.Write();
            //a24rw.Close();
        }

        private void MenuItemAnalysis_SubNetwork_Click(object sender, RoutedEventArgs e)
        {
            //var sw = new SubNetworkWindow();
            //var result = sw.ShowDialog();

            //if (result.Value)
            //    Console.WriteLine("====== SubNetwork analysis is successfully completed.");
            //else
            //    Console.WriteLine("====== SubNetwork analysis is abnormally terminated.");
        }

        private void MenuItemAnalysis_CoxRegression_Click(object sender, RoutedEventArgs e)
        {
            var crw = new CoxRegressionWindow();
            var result = crw.ShowDialog();

            if (result.Value)
                Console.WriteLine("====== Cox regression analysis is successfully completed.");
            else
                Console.WriteLine("====== Cox regression analysis is abnormally terminated.");
        }

        #endregion

        #region Window menu methods

        private void MenuItemWindow_AutoHideAll_Click(object sender, RoutedEventArgs e)
        {
            //foreach (var content in AvalonDockHost.DockableContents)
            //    if (content.State != DockableContentState.AutoHide)
            //        content.ToggleAutoHide();
        }

        private void MenuItemWindow_NewHorizontalTabGroup_Click(object sender, RoutedEventArgs e)
        {
            //_documentPane.CreateNewHorizontalTabGroup();
        }

        private void MenuItemWindow_NewVerticalTabGroup_Click(object sender, RoutedEventArgs e)
        {
            //_documentPane.CreateNewVerticalTabGroup();
        }

        private void MenuItemWindow_CloseAllDocuments_Click(object sender, RoutedEventArgs e)
        {
            //foreach (var document in AvalonDockHost.Documents)
            //    document.Close();
        }

        #endregion

        #region Help menu methods

        private void MenuItemHelp_About_Click(object sender, RoutedEventArgs e)
        {
            var aw = new AboutWindow();
            aw.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            aw.ResizeMode = System.Windows.ResizeMode.NoResize;
            aw.ShowDialog();
        }

        private void HelpCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            var hw = new HelpWindow();
            hw.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            hw.Show();
        }

        #endregion

        #region Search menu method

        public uint RelationType
        {
            get
            {
                RelationTypes relationTypes = RelationTypes.None;

                if (_cbDatabaseGXPCC.IsChecked.Value)
                    relationTypes |= RelationTypes.GX_PCC;
                if (_cbDatabaseGXMI.IsChecked.Value)
                    relationTypes |= RelationTypes.GX_MI;
                if (_cbDatabaseLitNLP.IsChecked.Value)
                    relationTypes |= RelationTypes.Lit_NLP;
                if (_cbDatabaseLitNCBI.IsChecked.Value)
                    relationTypes |= RelationTypes.Lit_NCBI;
                if (_cbDatabaseLitComentioned.IsChecked.Value)
                    relationTypes |= RelationTypes.Lit_Comentioned;
                if (_cbDatabasePPIHPRD.IsChecked.Value)
                    relationTypes |= RelationTypes.PPI_HPRD;
                if (_cbDatabasePPIIntAct.IsChecked.Value)
                    relationTypes |= RelationTypes.PPI_IntAct;
                if (_cbDatabasePPIREACTOME.IsChecked.Value)
                    relationTypes |= RelationTypes.PPI_REACTOME;
                if (_cbDatabasePPIMINT.IsChecked.Value)
                    relationTypes |= RelationTypes.PPI_MINT;
                if (_cbDatabasePPIMIPS.IsChecked.Value)
                    relationTypes |= RelationTypes.PPI_MIPS;
                if (_cbDatabasePPIDIP.IsChecked.Value)
                    relationTypes |= RelationTypes.PPI_DIP;
                if (_cbDatabasePPIKEGG.IsChecked.Value)
                    relationTypes |= RelationTypes.PPI_KEGG;
                if (_cbDatabaseTFJASPAR.IsChecked.Value)
                    relationTypes |= RelationTypes.TF_JASPAR;
                if (_cbDatabaseTFPANTHER.IsChecked.Value)
                    relationTypes |= RelationTypes.TF_PANTHER;
                if (_cbDatabaseTFKEGG.IsChecked.Value)
                    relationTypes |= RelationTypes.TF_KEGG;
                if (_cbDatabaseTFPAP.IsChecked.Value)
                    relationTypes |= RelationTypes.TF_PAP;

                return (uint)relationTypes;
            }
        }

        private void Search()
        {
            var annotations = new Annotations_Human();

            // Parses input gene symbols
            char[] delimiters = ";:,|\t".ToCharArray();
            string[] inputGenes = _tbInputGenes.Text.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);

            // Temp variables
            IEnumerable<int> geneIds;

            if (inputGenes.Length > 0)
            {
                switch (_cbTargetType.SelectedIndex)
                {
                    case 0:
                        geneIds = annotations.Symbol2ID.Where(s2i => inputGenes.Contains(s2i.Symbol)).Select(s2i => s2i.ID).ToArray();
                        break;
                    case 1:
                    default:
                        geneIds = inputGenes.Select(inputGene => Int32.Parse(inputGene));
                        break;
                }

                if (geneIds.Count() > 0)
                {
                    var network = Network.Search(geneIds, RelationType);
                    if (network != null)
                    {
                        network.Annotate();

                        if (_cbTargetType.SelectedIndex == 0)
                            network.Name = (inputGenes.Length > 1) ? String.Format("{0}...", inputGenes[0]) : inputGenes[0];
                        else
                        {
                            var inputGene = annotations.GeneInfo.Single(gi => gi.ID.Equals(inputGenes[0])).Symbol;
                            network.Name = (inputGenes.Length > 1) ? String.Format("{0}...", inputGene) : inputGene;
                        }

                        ViewModel.OpenNetwork(network, String.Format("{0}.xml", network.Name));
                        //ApplyGeneValue("C:\\Command_Console\\Data\\TCGA200\\GX\\Survival\\gene_metzeler_training_featurescore.txt", network, "Cox");
                        //ApplyGeneValue2(network, "Coverage");
//                        OpenNetwork(network);
                    }
                    else
                    {
                        Console.WriteLine("No network is found!");
                    }
                }
            }
        }

        private void SearchCommandExecute(object sender, ExecutedRoutedEventArgs e)
        {
            Search();
            _tbInputGenes.Clear();
        }

        private void _tbInputGenes_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                Search();
                _tbInputGenes.Clear();
            }
        }

        private void MenuItemSearch_CNAML_Click(object sender, RoutedEventArgs e)
        {
            var network = CNAMLNetwork.GetNetwork();
            OpenNetwork(network);
        }

        #endregion

        #region Move menu methods

        private void UpCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (_avalonDockHost.ActiveDocument != null)
            {
                var networkDocument = _avalonDockHost.ActiveDocument as NetworkDocument;
                networkDocument._zoomControl.TranslateY -= 1;
            }
        }

        private void DownCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (_avalonDockHost.ActiveDocument != null)
            {
                var networkDocument = _avalonDockHost.ActiveDocument as NetworkDocument;
                networkDocument._zoomControl.TranslateY += 1;
            }
        }

        private void RightCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (_avalonDockHost.ActiveDocument != null)
            {
                var networkDocument = _avalonDockHost.ActiveDocument as NetworkDocument;
                networkDocument._zoomControl.TranslateX += 1;
            }
        }

        private void LeftCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (_avalonDockHost.ActiveDocument != null)
            {
                var networkDocument = _avalonDockHost.ActiveDocument as NetworkDocument;
                networkDocument._zoomControl.TranslateX -= 1;
            }
        }

        #endregion

        #region Layout methods

        private void SaveLayout(object sender, RoutedEventArgs e)
        {
            //AvalonDockHost.SaveLayout(LayoutFile);
        }

        private void RestoreLayout(object sender, RoutedEventArgs e)
        {
            //if (File.Exists(LayoutFile))
            //    AvalonDockHost.RestoreLayout(LayoutFile);
        }

        #endregion

        #endregion

        #region Public Methods

        public void OpenNetwork(Network network)
        {
            ViewModel.OpenFile();
            //ViewModel.Project.AddNetwork(network);
            
            var document = new NetworkDocument();
            //document.DataContext = new NetworkDocumentViewModel(network);
            //_documentPane.Items.Add(document);
            //document.Activate();

            //Console.WriteLine("{0} was successfully opened.", network);
        }

        public void OpenSubNetworkResult(SubNetworkResult result)
        {
            var document = new SubNetworksDocument {DataContext = result};
            //_documentPane.Items.Add(document);
            document.Activate();
        }

        #endregion
    }
}
